package org.skydiveapplibrary.util;

import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.skydiveapplibrary.R;
import org.skydiveapplibrary.data.LogEntryImage;
import org.skydiveapplibrary.repository.LogEntryRepository;
import org.skydiveapplibrary.util.DatabaseImportUtil;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.widget.Toast;

public class ImportTask extends AsyncTask<ImportSource, ImportTask.TaskProgress, Integer>
{
    // message types
    private static final int SUCCESS = 11;
    private static final int ERROR = 21;

    // import file names
	private static final String XML_FILE_NAME = "skydiving_logbook.xml";
	private static final String ZIP_FILE_NAME = "skydiving_logbook.zip";
	
    // dropbox folder
    private static final String DROPBOX_FOLDER = "skydiving_logbook";

    public static class TaskProgress {
        final int percentage;
        final String message;

        TaskProgress(int percentage, String message) {
            this.percentage = percentage;
            this.message = message;
        }
    }
    
    // image import info delegate
    private ImageImportDelegate _imageImportDelegate = new ImageImportDelegate()
    {
		@Override
		public void addImageImportInfo(ImageImportInfo info)
		{
			_imageImportInfo.add(info);
		}
    };

    private Activity mActivity;
    private FileManager mFileManager;
    private DropBoxClient mDropBoxClient;
    private ProgressDialog mProgressDialog = null;
    private List<ImageImportInfo> _imageImportInfo = new ArrayList<ImageImportInfo>();
	
    public ImportTask(Activity activity)
    {
        mActivity = activity;
        mFileManager = new FileManager(activity);
        mDropBoxClient = new DropBoxClient(activity);
    }
    
	@Override
	protected void onPreExecute()
	{		
		// show dialog
		mProgressDialog = new ProgressDialog(new ContextThemeWrapper(mActivity, R.style.DialogStyle));
        mProgressDialog.setTitle(mActivity.getString(R.string.import_export_import_progress_message));
        mProgressDialog.setMessage("");
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setCancelable(false);
        mProgressDialog.show();
        
		// clear image import info
		_imageImportInfo.clear();
	}
	
	@Override
	protected Integer doInBackground(ImportSource... sources)
	{
		int result = SUCCESS;

		ImportSource source = sources[0];
		try
		{
			if (source == ImportSource.SDCard)
			{
				result = importFromSDCard();
			}
			else if (source == ImportSource.DropBox)
			{
				result = importFromDropBox();
			}
		}
		catch (Exception ex)
		{
			Log.e(ImportTask.class.getCanonicalName(), ex.getMessage());
			result = ERROR;
		}
		
		return result;
	}
	
	@Override
	protected void onPostExecute(Integer result)
	{
		// dismiss dialog
		mProgressDialog.dismiss();
		
		// get resource for result
		int resourceId = (result == SUCCESS) ? R.string.import_export_import_success :
			R.string.import_export_import_error;
		
		// show toast
		Toast status = Toast.makeText(mActivity, resourceId, Toast.LENGTH_SHORT);
		status.show();
	}
	
	private int importFromSDCard()
		throws Exception
	{
		// first look for ZIP file
		File zipFile = mFileManager.getSDCardFile(ZIP_FILE_NAME);

		if (zipFile.exists())
		{
			publishProgress(
					new TaskProgress(
							0, 
							mActivity.getString(R.string.import_export_unzipping_files)));
			
			// unzip to app directory
			mFileManager.unzip(zipFile, mFileManager.getCacheDir());
			
			// get xml file
			File xmlFile = mFileManager.getCacheFile(XML_FILE_NAME);
			if (!xmlFile.exists())
				return ERROR;
			
			// do import
			publishProgress(
					new TaskProgress(
							0, 
							mActivity.getString(R.string.import_export_importing_log_entries)));
			
			DatabaseImportUtil importUtil = new DatabaseImportUtil(mActivity);
			importUtil.importXml(xmlFile, _imageImportDelegate, mProgressDialog);
			
			// import images
			importImages();
			
			// cleanup files
			mFileManager.deleteCacheFiles();
			
			return SUCCESS;
		}
		
		// if zip file not found, look for XML file
		File xmlFile = mFileManager.getSDCardFile(XML_FILE_NAME);
		if (xmlFile.exists())
		{
			// do import
			DatabaseImportUtil importUtil = new DatabaseImportUtil(mActivity);
			importUtil.importXml(xmlFile, _imageImportDelegate, mProgressDialog);
			
			// import images
			importImages();
			
			return SUCCESS;
		}
		
		return ERROR;
	}
	
	private int importFromDropBox()
		throws Exception
	{
		// get destination import file
		File xmlFile = mFileManager.getCacheFile(XML_FILE_NAME);
		// delete if it already exists
		if (xmlFile.exists())
		{
			xmlFile.delete();
		}
		
		// create blank file
		if (!xmlFile.exists())
		{
			xmlFile.createNewFile(); // otherwise dropbox client will fail silently
		}

		publishProgress(
				new TaskProgress(
						0, 
						mActivity.getString(R.string.import_export_downloading_log_entries)));
		
		// download from dropbox
		mDropBoxClient.getFile(DROPBOX_FOLDER, XML_FILE_NAME, xmlFile, mProgressDialog);

		publishProgress(
				new TaskProgress(
						100, 
						mActivity.getString(R.string.import_export_downloading_log_entries)));
		
		// do import
		publishProgress(
				new TaskProgress(
						0, 
						mActivity.getString(R.string.import_export_importing_log_entries)));
		DatabaseImportUtil importUtil = new DatabaseImportUtil(mActivity);
		importUtil.importXml(xmlFile, _imageImportDelegate, mProgressDialog);
		
		// download images to import
		downloadImages();
		
		// import images from app dir
		importImages();
		
		// cleanup app files
		mFileManager.deleteCacheFiles();

		return SUCCESS;
	}
	
	private void downloadImages()
			throws Exception
	{
		for (int i = 0; i < _imageImportInfo.size(); i++)
		{
			ImageImportInfo imageImport = _imageImportInfo.get(i);
			
			publishProgress(new TaskProgress(
					0,
					MessageFormat.format(
							mActivity.getString(R.string.import_export_downloading_image),
							new Object[] { i+1, _imageImportInfo.size()})));

			if (imageImport.getImage() == null)
			{
				// need to download
				// create local file
				File localFile = mFileManager.getCacheFile(imageImport.getFileName());
				// do download
				mDropBoxClient.getFile(DROPBOX_FOLDER, imageImport.getFileName(), localFile, mProgressDialog);
			}
			
		}
	}
	
	private void importImages()
			throws Exception
		{
			List<LogEntryImage> images = new ArrayList<LogEntryImage>();
			
			for (int i = 0; i < _imageImportInfo.size(); i++)
			{
				ImageImportInfo imageImport = _imageImportInfo.get(i);
				
				publishProgress(new TaskProgress(
						(int) ((i / (float) _imageImportInfo.size()) * 100),
						mActivity.getString(R.string.import_export_importing_images)));
				
				// create log entry image
				LogEntryImage image = new LogEntryImage();
				image.setImageType(imageImport.getImageType());
				image.setLogEntryId(imageImport.getLogEntryId());
				image.setMD5(imageImport.getMd5());
				File localFile;
				
				// if imageImport info already has image data
				if (imageImport.getImage() != null)
				{
					// write to ExternalStorage
					localFile = mFileManager.writeByteArrayToCacheDir(imageImport.getImage());
				}
				else
				{
					// otherwise look for local file
					
					// get local file
					localFile = mFileManager.getCacheFile(imageImport.getFileName());
					
					// skip if it doesn't exist
					if (!localFile.exists())
						continue;
				}
				
				String md5 = mFileManager.putStorageFileFromCache(localFile.getName());
				
				image.setMD5(md5);
				image.setFilename(md5 + ".jpg");

				// add to list
				images.add(image);
			}
			
			// save images
			LogEntryRepository repository = new LogEntryRepository(mActivity);
			repository.addLogEntryImages(images);
		}
	
	protected void setProgressMessage(TaskProgress progress)
	{
		mProgressDialog.setProgress(progress.percentage);
		mProgressDialog.setMessage(progress.message);
	}
	
	@Override
	protected void onProgressUpdate(TaskProgress... progress)
	{
		setProgressMessage(progress[0]);
    }
}